import struct
from uuid import UUID
from string import atoi

class Template(list):
    
    def __init__(self,id,name,klass="Low",trusted=False,encoding="Unencoded"):
        """initialize a packet template"""
        list.__init__(self)
        self.name = name
        self.klass = klass
        self.trusted = trusted
        self.encoding = encoding
        self._id = id

        self._blocks=[]
        self._blockmap={}

    def append(self,block):
        """add a block"""
        list.append(self,block)
        self._blockmap[block.name]=block

    addBlock = append

    def __len__(self):
        """compute length"""
        l=0
        for block in self: l+=len(block)
        return l


class Block(list):
    
    def __init__(self,name):
        """initialize a data block"""
        list.__init__(self)
        self.name = name
        self._fieldmap={}

    def append(self,field):
        """add a field"""
        list.append(self,field)
        self._fieldmap[field.name]=field

    addField = append

    def __len__(self):
        """compute length"""
        l=0
        for field in self:
            l+=len(field)
        return l



class MultipleBlock(Block):
    """a block of type multiple"""

    def __init__(self,name,multiplier):
        """initialize multiple block"""
        Block.__init__(self,name)
        self.multiplier = multiplier

class Field:

    def __init__(self, name):
        """store variable data"""
        self.name = name

    def __len__(self):
        """return the length"""
        return struct.calcsize(self.fmt)

    def toBytes(self,value):
        """convert a value according to the format"""
        return struct.pack(self.fmt,value)


class U32Field(Field):
    """a U32 field"""
    typ="U32"
    fmt=">L"

class U16Field(Field):
    """a U16 field"""
    typ="U16"
    fmt=">I"

class U8Field(Field):
    """a U8 field"""
    typ="U8"
    fmt=">H"

class LLUUIDField(Field):
    """a U8 field"""
    typ="LLUUID"

    def toBytes(self,value):
        """convert a UUID string"""
        return UUID(value).bytes

    def __len__(self):
        return 8

class FieldData:
    """models field data"""

    def __init__(self,field,value=None):
        """initialize field data"""
        self._field = field
        self._value=value

    def setValue(self,value):
        self._value = value

    def getValue(self):
        return self._value 

    value = property(getValue,setValue)

    def toBytes(self):
        """convert this to bytes"""
        return self._field.toBytes(self.value)

class BlockData:
    """models a data block for a message"""

    def __init__(self,block):
        """initialize block data"""
        self._block = block
        self._fieldlist = []

        for field in block:
            # TODO: handle variable and mutiple fields
            fieldData = FieldData(field)
            print field.name
            setattr(self, field.name, fieldData)
            self._fieldlist.append(fieldData)

    def toBytes(self):
        """return the byte representation"""
        d=""
        for fieldData in self._fieldlist:
            d+=fieldData.toBytes()
        return d 

class Message:
    """a message object"""

    def __init__(self,tmpl):
        """initialize a message according to a template"""
        self._tmpl = tmpl
        self._blocklist = []

        # initialize all blocks
        for block in tmpl:
            # TODO: handle variable and mutiple blocks
            print block.name
            blkData = BlockData(block)
            print blkData
            setattr(self,block.name,blkData)
            self._blocklist.append(blkData)

    def toBytes(self):
        """return the byte representation"""
        d=""
        for blkdata in self._blocklist:
            d+=blkdata.toBytes()
        return d 
        

if __name__=="__main__":
    #tmpl = Template("EconomyDataRequest","Low",False,"Unencoded")

    tmpl = Template(1,"CompleteAgentMovement","Low",False,"Unencoded") # TODO: make Unencoded a constant or just a BOOL
    agentdata = Block("AgentData")
    agent_uuid = "35353fa3-8303-4d1b-aa08-f54416c8c921"
    session_uuid = "35353fa3-8303-4d1b-aa08-f54416c8c921"
    agentdata.append(LLUUIDField("AgentID"))
    agentdata.append(LLUUIDField("SessionID"))
    agentdata.append(U32Field("CircuitCode"))
    tmpl.append(agentdata)

    # read it again
    for block in tmpl:
        print "found block %s" %block.name, len(block)
        for field in block:
            print ">> found field %s" %field.name
    
    print len(tmpl)

    # now some message sending example
    msg = Message(tmpl)
    msg.AgentData.AgentID.value=agent_uuid
    msg.AgentData.SessionID.value=session_uuid
    msg.AgentData.CircuitCode.value=56212

    from binascii import hexlify
    res=hexlify(msg.toBytes())
    i=0
    l=0
    import sys
    for r in res:
        sys.stdout.write(r)
        if i%4==3: 
            sys.stdout.write(" ")
        i+=1
        l+=1
        if l%32==0:
            sys.stdout.write("\n")
    print

    #block = msg.neighbourblock.new()
    #msg.neighbourblock[0].Test0 = 3 # block.Test0 = 3

            



